<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h2 data-lake-id="LAIQh" id="LAIQh"><span data-lake-id="u6342435c" id="u6342435c">背景</span></h2>
  <p data-lake-id="u110f7aa3" id="u110f7aa3"><br></p>
  <p data-lake-id="u29217794" id="u29217794"><span data-lake-id="uf3b3920e" id="uf3b3920e">我在淘天集团的金融风控技术团队，我们需要支撑某个金融产品，在下单核心链路上进行风控的决策，但是上游给我们的RT只有5ms。我们之前的决策链路还是比较复杂的，上下游包含了多个系统，想要抗住这5ms的RT基本上是不可能的。</span></p>
  <p data-lake-id="u19d486da" id="u19d486da"><br></p>
  <p data-lake-id="ueb20805f" id="ueb20805f"><span data-lake-id="u40a73b88" id="u40a73b88">为了实现这个要求，我们单独做了一个前置决策，专门用来支持交易核心链路上的金融产品的风险防控及价格咨询。为了尽可能的提升性能，我们在过程中做了很多事情。最近业务已经上线了，也做了压测，基本满足了要求。于是总结一下本次的技术改造过程。</span></p>
  <p data-lake-id="u3befb100" id="u3befb100"><br></p>
  <h2 data-lake-id="7b680293" id="7b680293"><span data-lake-id="u3cef5037" id="u3cef5037">压测数据</span></h2>
  <p data-lake-id="u64251c4e" id="u64251c4e"><br></p>
  <p data-lake-id="u992c0540" id="u992c0540"><span data-lake-id="uceb8cd17" id="uceb8cd17">机器：4台<br>
    QPS：600（更新：同样的配置，后来我压到了3000，完全扛得住）<br>
    RT：2.38ms</span></p>
  <p data-lake-id="u46b68b80" id="u46b68b80"><br></p>
  <p data-lake-id="u1924caed" id="u1924caed"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1700992927382-bb098bb4-381a-46f8-a742-25b513f123e3.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_66%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u6f5f98a6" id="u6f5f98a6"><br></p>
  <p data-lake-id="ub99a96c8" id="ub99a96c8"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1700992927430-59477216-c445-4932-a57a-7d2376946d21.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_67%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u23f1eafc" id="u23f1eafc"><br></p>
  <p data-lake-id="u1de182fd" id="u1de182fd"><span data-lake-id="ufe375bab" id="ufe375bab">CPU：2.95%<br></span><span data-lake-id="ubf1a856b" id="ubf1a856b">MEM：29%<br></span><span data-lake-id="ue9931baa" id="ue9931baa">LOAD：0.05-0.25</span></p>
  <p data-lake-id="u25696153" id="u25696153"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1700992840224-61e4ee99-2629-4627-9b6d-ec113f5b551a.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_67%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="ubecfda34" id="ubecfda34"><br></p>
  <p data-lake-id="u1dd99559" id="u1dd99559"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1700992855459-917f4e6e-17a9-47a6-b6e7-c85a847ecaae.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_35%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <h2 data-lake-id="0cf2ebd5" id="0cf2ebd5"><span data-lake-id="u0a56f4af" id="u0a56f4af">调用链路</span></h2>
  <p data-lake-id="u8d188c46" id="u8d188c46"><br></p>
  <p data-lake-id="u4e41dbff" id="u4e41dbff"><br></p>
  <p data-lake-id="u77069831" id="u77069831"><br></p>
  <h2 data-lake-id="4d861e69" id="4d861e69"><span data-lake-id="u63f8e7ed" id="u63f8e7ed">技术方案</span></h2>
  <p data-lake-id="u6de37958" id="u6de37958"><br></p>
  <p data-lake-id="u5ef701e9" id="u5ef701e9"><span data-lake-id="u95fca893" id="u95fca893">整体的技术方案，主要做了这么多事情：</span><strong><span data-lake-id="u563a9149" id="u563a9149">独立部署+单元化架构+内存决策+多级缓存+异步日志+批量读取+数据预读</span></strong></p>
  <p data-lake-id="u789aba4b" id="u789aba4b"><br></p>
  <h3 data-lake-id="ed7e0f37" id="ed7e0f37"><span data-lake-id="u041cf29f" id="u041cf29f">独立部署+单元化架构</span></h3>
  <p data-lake-id="u2a069fc2" id="u2a069fc2"><br></p>
  <p data-lake-id="u946d4723" id="u946d4723"><span data-lake-id="ue07879b8" id="ue07879b8">单独创建一个应用，做单元化部署，避免和其他业务之间互相影响，可以快速迭代进行发布。</span></p>
  <p data-lake-id="ud95a96b5" id="ud95a96b5"><span data-lake-id="ub97a5efc" id="ub97a5efc">​</span><br></p>
  <p data-lake-id="u38fbbbdd" id="u38fbbbdd"><br></p>
  <p data-lake-id="u4998c21f" id="u4998c21f"><span data-lake-id="u7ee10599" id="u7ee10599">前置决策：包含风控、定价等金融决策功能。<br></span><span data-lake-id="u095d25c9" id="u095d25c9">同单元网络延迟：同机房0.2ms，跨机房0.8ms</span></p>
  <p data-lake-id="u8edfdcf9" id="u8edfdcf9"><br></p>
  <h3 data-lake-id="7c855abe" id="7c855abe"><span data-lake-id="ub2afdbd8" id="ub2afdbd8">内存决策</span></h3>
  <p data-lake-id="udeade075" id="udeade075"><br></p>
  <p data-lake-id="ua63b6934" id="ua63b6934"><span data-lake-id="u4d460cdc" id="u4d460cdc">放弃原来的链路，改为内部自决策。数据从缓存读取，决策在内存进行。不外调，不外查。</span></p>
  <p data-lake-id="u09451978" id="u09451978"><br></p>
  <h3 data-lake-id="94065487" id="94065487"><span data-lake-id="uadd2ca7a" id="uadd2ca7a">多级缓存</span></h3>
  <p data-lake-id="u1f7fa982" id="u1f7fa982"><br></p>
  <p data-lake-id="uf1d2c106" id="uf1d2c106"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1700992927425-d79c24ee-029c-4fe1-93fe-bacbcbcde12e.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_21%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="uce710e21" id="uce710e21"><br></p>
  <p data-lake-id="u17e584c4" id="u17e584c4"><span data-lake-id="u6a27f973" id="u6a27f973">本地缓存：Caffeine</span></p>
  <p data-lake-id="u60f2cb55" id="u60f2cb55"><br></p>
  <ul list="u5a584943">
   <li fid="ue74a2f67" data-lake-id="uf2e23ae4" id="uf2e23ae4"><span data-lake-id="u0fccecd1" id="u0fccecd1">保存最近的决策因子——名单值<br></span><span data-lake-id="u1ec07af2" id="u1ec07af2">Tair客户端本地缓存：tair local cache</span></li>
   <li fid="ue74a2f67" data-lake-id="u66c157dd" id="u66c157dd"><span data-lake-id="u726df889" id="u726df889">热点检测，针对热点数据做本地缓存<br></span><span data-lake-id="uae28f175" id="uae28f175">Tair分布式缓存：LDB</span></li>
   <li fid="ue74a2f67" data-lake-id="u755f2fca" id="u755f2fca"><span data-lake-id="u8c6a58e8" id="u8c6a58e8">分布式缓存，做缓存数据持久化及一致性保障</span></li>
  </ul>
  <p data-lake-id="u1f232e3f" id="u1f232e3f"><br></p>
  <p data-lake-id="u63089818" id="u63089818"><br></p>
  <p data-lake-id="uf9c104a4" id="uf9c104a4"><br></p>
  <p data-lake-id="uc93f4103" id="uc93f4103"><span data-lake-id="ud795a9d4" id="ud795a9d4">代码：</span></p>
  <p data-lake-id="uf28259df" id="uf28259df"><br></p>
  <pre lang="java"><code>
@Override
public DecisionContext initContext(List&lt;RiskAdmitRequest&gt; riskAdmitRequests, String localCacheNamespace, int remoteCacheNamespace) {

    DecisionContext decisionContext = new DecisionContext();
    //初始化上下文
    decisionContext.setLocalCacheNamespace(localCacheNamespace);
    decisionContext.setRemoteCacheNamespace(remoteCacheNamespace);
    DecisionConfig decisionConfig = decisionConfigProperties.getDecisionConfig(localCacheNamespace);

    //key添加
    enrichKeys(decisionContext, riskAdmitRequests, decisionConfig);

    //从本地缓存中查询

    fetchLocalCache(decisionContext);

    //从分布式缓存中查询
    fetchRemoteCache(decisionContext);

    if (logger.isInfoEnabled()) {
        logger.info(decisionContext.printLog());
    }
    return decisionContext;
}
</code></pre>
  <p data-lake-id="u341d2435" id="u341d2435"><br></p>
  <h4 data-lake-id="8a67cc2a" id="8a67cc2a"><span data-lake-id="ubfcb963b" id="ubfcb963b">缓存更新方案</span></h4>
  <p data-lake-id="u4ecf018b" id="u4ecf018b"><br></p>
  <p data-lake-id="u92b6371a" id="u92b6371a"><span data-lake-id="u706c9c22" id="u706c9c22">离线数仓直接通过定时任务写数据到tair缓存中。（这里用了内部工具，就不展开说了）</span></p>
  <p data-lake-id="ud3d21bf0" id="ud3d21bf0"><br></p>
  <p data-lake-id="ubf5e5aae" id="ubf5e5aae"><span data-lake-id="ucb72e1eb" id="ucb72e1eb">任务调度：1200万数据，耗时7分钟</span></p>
  <p data-lake-id="ucb204c16" id="ucb204c16"><br></p>
  <h4 data-lake-id="496b2ce0" id="496b2ce0"><span data-lake-id="u04f812c5" id="u04f812c5">缓存替换方案</span></h4>
  <p data-lake-id="ucf269781" id="ucf269781"><br></p>
  <p data-lake-id="u4ebfe105" id="u4ebfe105"><span data-lake-id="u16546034" id="u16546034">采用增量更新，每天全量刷进LDB缓存中，数据不做主动删除。可避免和解决以下问题：<br></span><span data-lake-id="udac6af7e" id="udac6af7e">1、如果当日调度失败，不会导致缓存被击穿。<br></span><span data-lake-id="u1dac4fbb" id="u1dac4fbb">2、不需要做版本切换，版本切换和数据同步无法保证原子性，时效性也无法保证<br></span><span data-lake-id="u00626f45" id="u00626f45">3、避免缓存刷新过程对应用自身造成影响</span></p>
  <p data-lake-id="ube7523e9" id="ube7523e9"><br></p>
  <p data-lake-id="uf57e121a" id="uf57e121a"><span data-lake-id="u64191d67" id="u64191d67">主要SQL如下：</span></p>
  <p data-lake-id="uad78ded9" id="uad78ded9"><br></p>
  <pre lang="java"><code>
-- 买家黑名单
insert overwrite table  tao_decision_cache  PARTITION(ds = '${bizdate}')
SELECT  CONCAT("JBZ_BL_BYR_" , user_id) as key
        ,CASE    blk_flag
                WHEN 'Y' THEN code_str
                ELSE NULL
        END AS value
FROM    b2b_risk.dwi_cf_tb_byr_jbz_item_detail_black_list_df
WHERE   ds = '${bizdate}'
</code></pre>
  <p data-lake-id="uecb7979d" id="uecb7979d"><br></p>
  <p data-lake-id="u45f2d361" id="u45f2d361"><span data-lake-id="u5565fff7" id="u5565fff7">产出数据如下：</span></p>
  <p data-lake-id="u0f2f4643" id="u0f2f4643"><br></p>
  <p data-lake-id="uf0d09994" id="uf0d09994"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1700992927948-66ee0c69-86d3-4ceb-9bdb-c6285f0d5f16.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_22%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="uc496710b" id="uc496710b"><br></p>
  <p data-lake-id="ue0414add" id="ue0414add"><span data-lake-id="u6a91857d" id="u6a91857d">直接把当日分区中的所有数据，直接刷入到Tair中，value为\N时会自动删除数据</span></p>
  <p data-lake-id="u2905fa4c" id="u2905fa4c"><br></p>
  <h4 data-lake-id="1c9c9805" id="1c9c9805"><span data-lake-id="u37ddebbd" id="u37ddebbd">Why LDB</span></h4>
  <p data-lake-id="u66b8bf19" id="u66b8bf19"><br></p>
  <p data-lake-id="ud6133148" id="ud6133148"><span data-lake-id="ue9ebaf64" id="ue9ebaf64">1、Redis 3.0 不支持单元化部署，需要自己拉多个集群，进行同步配置。<br></span><span data-lake-id="u7a17bb62" id="u7a17bb62">2、Redis 3.0 贵，同样规格，是LDB的几倍价格<br></span><span data-lake-id="u2470e803" id="u2470e803">3、LDB也能满足性能要求</span></p>
  <p data-lake-id="ufb629f61" id="ufb629f61"><br></p>
  <h4 data-lake-id="ad9b7b63" id="ad9b7b63"><span data-lake-id="u684100f2" id="u684100f2">tair local cache</span></h4>
  <p data-lake-id="u1c8445fa" id="u1c8445fa"><br></p>
  <p data-lake-id="u5d8df035" id="u5d8df035"><span data-lake-id="uf7677306" id="uf7677306">本地创建了基于LRU的队列（使用LinkedHashMap实现），通过过期时间和队列大小两个方面对缓存entry的剔除进行控制。当达到队列大小阀值时，新进的entry会被LRU算法淘汰；当entry在队列中存在时间超过过期时间阀值时，也会被淘汰。</span></p>
  <p data-lake-id="u58e97de7" id="u58e97de7"><br></p>
  <p data-lake-id="uf471ee1d" id="uf471ee1d"><span data-lake-id="ud547c0aa" id="ud547c0aa">缺点：数据一致性问题</span></p>
  <p data-lake-id="u86d9dc95" id="u86d9dc95"><br></p>
  <h3 data-lake-id="7b5a9fd0" id="7b5a9fd0"><span data-lake-id="u7ad88357" id="u7ad88357">异步日志</span></h3>
  <p data-lake-id="u7ed04ef0" id="u7ed04ef0"><br></p>
  <p data-lake-id="u160a345f" id="u160a345f"><span data-lake-id="ua0836dfe" id="ua0836dfe">使用异步日志进行输出时，日志输出语句与业务逻辑语句并不是在同一个线程中运行，而是有专门的线程用于进行日志输出操作，处理业务逻辑的主线程不用等待即可执行后续业务逻辑。这样即使日志没有完成输出，也不会影响程序的主业务，从而提高了程序的性能。</span></p>
  <p data-lake-id="ua755e4f4" id="ua755e4f4"><br></p>
  <p data-lake-id="uf72cc5e3" id="uf72cc5e3"><span data-lake-id="u41b75a76" id="u41b75a76">logback异步输出日志是通过AsyncAppender实现的。Logback的异步输出采用生产者消费者的模式，将生成的日志放入消息队列中，并将创建一个线程用于输出日志事件。</span></p>
  <p data-lake-id="ud13c643b" id="ud13c643b"><br></p>
  <pre lang="java"><code>
  &lt;appender name="ASYNC-APPLICATION" class="ch.qos.logback.classic.AsyncAppender"&gt;
      &lt;discardingThreshold&gt;0&lt;/discardingThreshold&gt;
      &lt;queueSize&gt;512&lt;/queueSize&gt;
      &lt;neverBlock&gt;true&lt;/neverBlock&gt;
      &lt;appender-ref ref="APPLICATION"/&gt;
  &lt;/appender&gt;
</code></pre>
  <p data-lake-id="u5726b542" id="u5726b542"><br></p>
  <h3 data-lake-id="4a4309e6" id="4a4309e6"><span data-lake-id="u199203b6" id="u199203b6">批量读取</span></h3>
  <p data-lake-id="ucf6fe12e" id="ucf6fe12e"><br></p>
  <p data-lake-id="u81ddd456" id="u81ddd456"><span data-lake-id="u1dc98f46" id="u1dc98f46">因为一次决策需要涉及到多个数据指标的读取，于是在缓存中读取key时，采用批量读取的方式。可以减少网络开销。</span></p>
  <p data-lake-id="udd4e252e" id="udd4e252e"><br></p>
  <pre lang="java"><code>
  /**
   * Returns a map of the values associated with the {@code keys} in this cache. The returned map
   * will only contain entries which are already present in the cache.
   * &lt;p&gt;
   * Note that duplicate elements in {@code keys}, as determined by {@link Object#equals}, will be
   * ignored.
   *
   * @param keys the keys whose associated values are to be returned
   * @return the unmodifiable mapping of keys to values for the specified keys found in this cache
   * @throws NullPointerException if the specified collection is null or contains a null element
   */

com.github.benmanes.caffeine.cache.Cache#getAllPresent
</code></pre>
  <p data-lake-id="u83e18388" id="u83e18388"><br></p>
  <h3 data-lake-id="28280a33" id="28280a33"><span data-lake-id="uf553abfc" id="uf553abfc">数据预读</span></h3>
  <p data-lake-id="ua68c7af1" id="ua68c7af1"><br></p>
  <p data-lake-id="u964371d3" id="u964371d3"><span data-lake-id="u9e1c17b8" id="u9e1c17b8">在决策前，先把需要的数据准备好，先进行数据的预读准备，然后进行决策。在做这个过程中，通过Future来进行并发执行。</span></p>
  <p data-lake-id="ufc9554e7" id="ufc9554e7"><br></p>
  <pre lang="java"><code>
//前置校验
riskDecisionStrategyService.preCheck(request, decisionCode);

//初始化上下文
Future&lt;DecisionContext&gt; decisionContext = decisionInitContextPool.submit(() -&gt; {
    return riskDecisionStrategyService.initContext(ImmutableList.of(request), decisionCode, remoteCacheNamespace);
});

//执行决策
RiskAdmitResponse response = riskDecisionStrategyService.admit(request, decisionContext);
</code></pre>
  <p data-lake-id="u905c7b0a" id="u905c7b0a"><br></p>
  <h4 data-lake-id="ddb6ca79" id="ddb6ca79"><span data-lake-id="u4ba35230" id="u4ba35230">traceId透传</span></h4>
  <p data-lake-id="uc0347339" id="uc0347339"><br></p>
  <p data-lake-id="u798faeed" id="u798faeed"><span data-lake-id="u4101abe7" id="u4101abe7">线程池中，traceId会丢失，试了多种方式，包括TTL、logback-mdc-ttl等均不生效，于是手动设置：</span></p>
  <p data-lake-id="u43492903" id="u43492903"><br></p>
  <pre lang="java"><code>
RpcContext_inner rpcContext = EagleEye.getRpcContext();

//初始化上下文
Future&lt;DecisionContext&gt; decisionContext = decisionInitContextPool.submit(() -&gt; {
    EagleEye.setRpcContext(rpcContext);
    return riskDecisionStrategyService.initContext(ImmutableList.of(request), decisionCode, remoteCacheNamespace);
});
</code></pre>
  <p data-lake-id="u8c5f643f" id="u8c5f643f"><br></p>
  <h3 data-lake-id="cc136a96" id="cc136a96"><span data-lake-id="u6bafa919" id="u6bafa919">缓存重建</span></h3>
  <p data-lake-id="ua73a49eb" id="ua73a49eb"><br></p>
  <p data-lake-id="u18e96ced" id="u18e96ced"><span data-lake-id="ue36a5e69" id="ue36a5e69">本来想在业务中使用BloomFilter，但是后来发现数据量并不大，于是并没有使用，</span></p>
  <p data-lake-id="u0bee3375" id="u0bee3375"><br></p>
  <p data-lake-id="ub39f9dd0" id="ub39f9dd0"><span data-lake-id="u2d3d0ac2" id="u2d3d0ac2">BloomFilter的特点就是基于BitMap实现，占用内存小、但是有一定的误判率，适合黑名单场景，但是不支持删除，只支持添加，只能进行重建。</span></p>
  <p data-lake-id="u24b30562" id="u24b30562"><br></p>
  <p data-lake-id="uafd649bf" id="uafd649bf"><span data-lake-id="u6bc40ec0" id="u6bc40ec0">于是设计了BloomFilter的缓存重建策略：</span></p>
  <p data-lake-id="u9c22c529" id="u9c22c529"><br></p>
  <p data-lake-id="u72bae046" id="u72bae046"><br></p>
  <p data-lake-id="u4df40d0c" id="u4df40d0c"><br></p>
  <h3 data-lake-id="28a769bc" id="28a769bc"><span data-lake-id="u9a7d2451" id="u9a7d2451">规则配置</span></h3>
  <p data-lake-id="u591850f4" id="u591850f4"><br></p>
  <p data-lake-id="u3056e5b5" id="u3056e5b5"><span data-lake-id="ufee7364e" id="ufee7364e">基于Yaml文件配置出风控决策规则，可以做到规则集中配置、可视化、易调整：</span></p>
  <p data-lake-id="u5926cf23" id="u5926cf23"><br></p>
  <pre lang="java"><code>
decisions:
  - product: JBZ
    method: admit
    scene: RENDER_ADMIT
    cacheName: JBZ_admit_RENDER_ADMIT
    blackList:
      - name: buyerId
        localCache:
          cacheType: CAFFEINE
          rebuild: false
#          cacheType: BLOOM_FILTER
#          rebuild: true
#          expectedInsertions: 300000000
#          fpp: 0.01
#          rebuildFilePath: risk/jbz/
#          filePrefix: buyer_black_list__

        prefix: JBZ_BL_BYR_
        keyPropertyPath: $.buyerId
        required: true
      - name: buyerSellerId
        localCache:
          cacheType: CAFFEINE
          rebuild: false
        prefix: JBZ_BL_BYR_SLR_
        keyPropertyPath: $.buyerSellerId
        required: true
      - name: phone
        localCache:
          cacheType: CAFFEINE
          rebuild: false
        prefix: JBZ_BL_TEL_
        keyPropertyPath: $.extendInfo.phone
        keyEncryptionAlgorithm: MD5_LOWER
        required: true
#    valueMatch:
#      - name: SKU_PRICE
#        localCache:
#          cacheType: CAFFEINE
#          rebuild: false
#        prefix: JBZ_PRC_SKU_
#        upperLimit: 1.5
#        keyPropertyPath: $.extendInfo.skuId
#        valuePropertyPath: $.extendInfo.skuPrice
#        required: false
</code></pre>
  <p data-lake-id="ua086b33a" id="ua086b33a"><br></p>
  <h4 data-lake-id="d9394afc" id="d9394afc"><span data-lake-id="u2caf4992" id="u2caf4992">参数解析</span></h4>
  <p data-lake-id="u4b155dd5" id="u4b155dd5"><br></p>
  <p data-lake-id="ubafc1ada" id="ubafc1ada"><span data-lake-id="u5e1c9b77" id="u5e1c9b77">基于JSONPath进行参数解析，在配置文件中只需要配置参数读取的路径即可，如$.buyerId 、 $.extendInfo.phone等。</span></p>
 </body>
</html>